09. 循环语句-股价涨跌幅提醒

本章概要

  • 学习材料:按日期排列的价格与涨跌幅序列。
  • 本章任务:运行 cell-stock-monitoring-loop,用 for、continue 与 break 逐日扫描异常。
  • 完成后你将得到:逐日检查记录、首次出现预警的日期,以及没有出现预警时的结果。
  • 自我检查:与向量化布尔结果核对首次命中;日期乱序或循环无结束条件时先检查原因。
  • 拓展练习:把监控循环拓展应用到另一只中国股票。

循环:批量金融数据处理的核心工具

金融市场产生海量时间序列数据——股价、成交量、收益率等。

  • 循环结构使我们能够高效处理重复性数据
  • 自动执行批量任务,是金融分析系统的核心工具
  • 本章重点:for循环、while循环与循环控制语句

迭代 vs 递归:两种重复执行模式

模式 含义 金融场景适用性
迭代 重复执行相同操作 ✅ 时间序列天然顺序性
递归 函数调用自身 ❌ 内存消耗大
  • 金融数据处理中,迭代(循环)更为常见
  • 内存消耗可控,更容易理解和调试

For循环:遍历序列的基本语法

for循环用于遍历列表、元组、字符串等可迭代对象。

语法结构:

for item in iterable:
    # 对每个元素执行操作
    pass  # 此处留给学习者填写逐项处理逻辑
  • item:每次迭代取出的当前元素
  • iterable:被遍历的序列对象

For循环:四种基本遍历方式

Listing 1: For循环的基本语法与遍历
展开代码
# ==================== 示例1:遍历列表 ====================
stocks = ['中信证券', '国泰君安', '海通证券']
for stock in stocks:
    print(f'分析股票: {stock}')

# ==================== 示例2:遍历字符串 ====================
code = '600519.SH'
for char in code:
    print(char, end=' ')
print()

# ==================== 示例3:遍历范围 ====================
for i in range(5):
    print(f'第{i+1}次迭代')

# ==================== 示例4:遍历字典 ====================
stock_info = {'name': '中信证券', 'code': '600030.SH', 'price': 24.78}
for key in stock_info:
    print(f'{key}: {stock_info[key]}')
分析股票: 中信证券
分析股票: 国泰君安
分析股票: 海通证券
6 0 0 5 1 9 . S H 
第1次迭代
第2次迭代
第3次迭代
第4次迭代
第5次迭代
name: 中信证券
code: 600030.SH
price: 24.78

range()函数:生成整数序列

range()是循环中最常用的工具,用于生成整数序列。

三种调用方式:

语法 说明 示例
range(stop) 从0到stop-1 range(5) → 0,1,2,3,4
range(start, stop) 从start到stop-1 range(2020, 2025)
range(start, stop, step) 指定步长 range(0, 10, 2)

range()函数:实例演示

Listing 2: range函数的多种用法
展开代码
# 用法1:指定结束值
for i in range(5):
    print(f'i = {i}', end='  ')
print()

# 用法2:指定起始和结束值(遍历年份)
for year in range(2020, 2025):
    print(f'年份: {year}')

# 用法3:指定步长(偶数序列)
for i in range(0, 10, 2):
    print(f'偶数: {i}', end='  ')
print()

# 用法4:负步长(倒序)
for i in range(10, 0, -1):
    print(f'倒计时: {i}', end=' ')
print()
i = 0  i = 1  i = 2  i = 3  i = 4  
年份: 2020
年份: 2021
年份: 2022
年份: 2023
年份: 2024
偶数: 0  偶数: 2  偶数: 4  偶数: 6  偶数: 8  
倒计时: 10 倒计时: 9 倒计时: 8 倒计时: 7 倒计时: 6 倒计时: 5 倒计时: 4 倒计时: 3 倒计时: 2 倒计时: 1 

range()金融应用:生成日期序列

Listing 3: 使用NumPy生成日期序列
展开代码
import numpy as np
dates = np.arange('2024-01-01', '2024-01-06', dtype='datetime64[D]')
print('2024年1月前5个工作日:')
for date in dates:
    print(f'  {date}')
2024年1月前5个工作日:
  2024-01-01
  2024-01-02
  2024-01-03
  2024-01-04
  2024-01-05
  • np.arange可生成日期范围,常用于时间序列分析
  • 配合for循环可逐日处理金融数据

While循环:条件驱动的重复执行

while循环在条件为True时重复执行,适用于不确定迭代次数的情况。

语法结构:

condition = True  # 设置一次可终止的演示条件
while condition:
    # 执行操作
    # 更新条件(重要!)
    condition = False  # 更新条件并保证示例终止
  • 循环条件最终必须变为False
  • 循环体内必须有更新条件的语句

While循环:简单计数示例

Listing 4: While循环基本计数
展开代码
count = 0
while count < 5:
    print(f'计数: {count}')
    count += 1  # 重要:更新循环变量,避免无限循环
# 循环执行5次后,count变为5,条件不再满足
计数: 0
计数: 1
计数: 2
计数: 3
计数: 4

While循环:模拟价格监控

Listing 5: While循环实现动态监控
展开代码
print('价格监控模拟:')
price = 18.00   # 初始价格
target = 20.00  # 目标价格
days = 0        # 天数计数器

while price < target:
    price += 0.50  # 每天价格上涨0.50元
    days += 1
    print(f'第{days}天, 价格: {price:.2f}元')

    if days > 100:  # 安全措施:避免无限循环
        print('达到最大监控天数')
        break

print(f'\n达到目标价20元, 耗时{days}天')
价格监控模拟:
第1天, 价格: 18.50元
第2天, 价格: 19.00元
第3天, 价格: 19.50元
第4天, 价格: 20.00元

达到目标价20元, 耗时4天

While循环:三条安全法则

使用while循环时,必须确保

  1. 循环条件最终会变为False
    • 否则将陷入无限循环
  2. 循环体内有更新条件的语句
    • count += 1price += 0.5
  3. 添加安全措施
    • 设置最大迭代次数:if days > 100: break

循环控制语句:break跳出循环

break语句立即跳出最内层循环,不执行循环体剩余代码。

执行逻辑:

  • 遇到break时,立即退出循环
  • 循环后续代码不再执行
  • 继续执行循环之后的语句

运行前预测|平台任务:股价跌幅预警(break)

  • 输入预测:运行前先写出 r_list 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到“涨跌幅数据”相关结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务:股价跌幅预警(break)”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务:股价跌幅预警(break)

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
r_list=[0.0192,-0.0001,0.006,0.0074,-0.0127,-0.0067,0.0095,-0.0095]  # 定义每日涨跌幅列表
for i in r_list:  # 逐日遍历涨跌幅数据
    if i<-0.01:  # 判断当日跌幅是否超过1%
        break  # 发现跌幅超限,立即跳出循环
print('涨跌幅数据',i)  # 输出达到跌幅提醒条件时的涨跌幅值

任务复盘|平台任务:股价跌幅预警(break)

运行后核对:核对 r_list 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:只改变一个关键输入或业务场景,先预测输出如何变化,再运行验证并解释变化原因。

平台任务代码深度解析

执行过程追踪:

  • 遍历 0.0192 → 不满足 < -0.01,继续
  • 遍历 -0.0001 → 不满足,继续
  • 遍历 0.006 → 不满足,继续
  • 遍历 0.0074 → 不满足,继续
  • 遍历 -0.0127满足! 执行break跳出

关键知识点: 循环变量i在循环外仍可访问,保持最后一次赋值

break的金融应用场景

场景 说明
达到风险提醒线 数据超过事先设定的范围时停止扫描并提示人工检查;不自动下单
异常检测 发现异常数据停止处理
检查完成 达到事先设定检查条件后退出循环并保存检查过程
  • break立即跳出最内层循环
  • 循环后的代码照常执行

循环控制语句:continue跳过当前迭代

continue语句跳过当前迭代的剩余代码,直接进入下一次迭代。

Listing 6: 使用continue跳过特定数据
展开代码
returns = [0.0192, -0.0001, 0.006, 0.0074, -0.0127, 0.0095]

print('正收益交易日:')
count = 0
for r in returns:
    if r < 0:       # 如果收益率为负
        continue    # 跳过本次迭代,直接进入下一次
    count += 1
    print(f'  第{count}个正收益日: {r:.2%}')

print(f'\n总计正收益日: {count}天')
正收益交易日:
  第1个正收益日: 1.92%
  第2个正收益日: 0.60%
  第3个正收益日: 0.74%
  第4个正收益日: 0.95%

总计正收益日: 4天

break vs continue 对比

关键字 作用 后续代码 循环是否继续
break 跳出整个循环 不执行 ❌ 否
continue 跳过本次迭代 不执行 ✅ 是
  • break:发现目标或异常,停止循环
  • continue:过滤数据,跳过不需要处理的部分

循环中的else子句

Python循环可以带else子句:循环正常结束时执行,被break中断时不执行

Listing 7: 循环else子句的使用
展开代码
# 场景1:循环正常结束 → 执行else
prices = [10, 11, 12, 13, 14]
for price in prices:
    if price > 20:
        print('发现高价股票')
        break
else:
    print('所有股票价格都在合理范围')

print('=' * 50)

# 场景2:循环被break中断 → 不执行else
prices2 = [10, 11, 25, 13, 14]
for price in prices2:
    if price > 20:
        print('发现高价股票')
        break
else:
    print('所有股票价格都在合理范围')
所有股票价格都在合理范围
==================================================
发现高价股票

循环else金融应用:数据验证

Listing 8: 使用循环else验证数据完整性
展开代码
prices = [24.78, 20.15, 14.03, 22.41, 16.17]

for price in prices:
    if price <= 0:
        print(f'发现异常价格: {price}')
        break
else:
    print('✓ 所有价格数据有效')
# 这种 for-else 模式在金融数据清洗中非常常用
✓ 所有价格数据有效
  • 循环正常结束(未发现异常)→ 执行else
  • 循环被break中断(发现异常)→ 跳过else

实战案例:股价涨跌幅监控系统

综合运用for循环、if条件判断、break语句:

  • 模拟一周股价数据,逐日计算涨跌幅并判断市场状态
  • 出现预警时自动停止循环(见下页说明)

股价监控系统:完整实现

展开完整参考实现
import numpy as np  # 导入NumPy以保存确定性课堂路径

# 构造无真实资产含义的一周课堂价格示例数据
prices = np.array([20.00,19.90,20.10,19.82,19.95])  # 固定输入以便逐日手工核对

print('=' * 60)
print('股价涨跌幅监控系统')
print('=' * 60)

alert_threshold = -0.01  # 跌幅超过-1%满足条件警报
============================================================
股价涨跌幅监控系统
============================================================

课堂价格路径:逐日监控循环

展开课堂监控循环
for i, price in enumerate(prices, 1):
    if i == 1:
        daily_return = 0
    else:
        daily_return = (price - prices[i-2]) / prices[i-2]

    return_pct = daily_return * 100

    if daily_return < alert_threshold:
        status = '⚠️ 阈值命中'; action = '进入风险核对'
    elif daily_return > 0.01:
        status = '✓ 正向变动'; action = '记录待检验'
    else:
        status = '区间内'; action = '继续记录'

    print(f'第{i}天: 收盘价{price:.2f}元|涨跌幅{return_pct:+.2f}%|{status}{action}')  # 单行输出当日摘要以控制输出高度

    if daily_return < alert_threshold:
        print('\n' + '=' * 60)
        print('课堂阈值满足条件,暂停并核对输入')
        print('=' * 60)
        break
else:
    print('\n' + '=' * 60)
    print('课堂路径遍历结束,未满足条件既定阈值')
    print('=' * 60)
第1天: 收盘价20.00元|涨跌幅+0.00%|区间内→继续记录
第2天: 收盘价19.90元|涨跌幅-0.50%|区间内→继续记录
第3天: 收盘价20.10元|涨跌幅+1.01%|✓ 正向变动→记录待检验
第4天: 收盘价19.82元|涨跌幅-1.39%|⚠️ 阈值命中→进入风险核对

============================================================
课堂阈值满足条件,暂停并核对输入
============================================================

注:示例序列没有达到 −1% 的提醒线;把提醒线改为 −0.3% 后再次运行,可以看到循环在首次预警时结束。

嵌套循环:处理二维数据

处理多只股票 × 多个交易日的数据时,需要使用嵌套循环。

执行逻辑:

  • 外层循环遍历交易日
  • 内层循环遍历每只股票
  • 时间复杂度为 \(O(n \times m)\)

嵌套循环:多股票收益统计

Listing 9: 嵌套循环处理多股票多日数据
展开代码
returns = [
    [0.01, 0.02, -0.01, 0.03, 0.02],   # 股票A
    [0.02, -0.01, 0.03, 0.01, -0.02],   # 股票B
    [-0.01, 0.03, 0.02, -0.02, 0.01]    # 股票C
]
stock_names = ['股票A', '股票B', '股票C']

print('每日正收益股票统计:\n')
for day in range(5):
    positive_count = 0
    positive_stocks = []
    for stock_idx in range(3):
        if returns[stock_idx][day] > 0:
            positive_count += 1
            positive_stocks.append(stock_names[stock_idx])
    print(f'第{day+1}天: {positive_count}只上涨 → {", ".join(positive_stocks)}')
每日正收益股票统计:

第1天: 2只上涨 → 股票A, 股票B
第2天: 2只上涨 → 股票A, 股票C
第3天: 2只上涨 → 股票B, 股票C
第4天: 2只上涨 → 股票A, 股票B
第5天: 2只上涨 → 股票A, 股票C

循环性能优化:四种方法对比

Listing 10: 循环与向量化的性能对比
展开完整参考实现
import time
import numpy as np

n = 100000
list1 = list(range(n))
list2 = list(range(n))

循环基准 1/2:Python 实现

Listing 11
展开Python实现计时
# 方法1:Python for循环
start = time.time()
result_loop = []
for i in range(n):
    result_loop.append(list1[i] + list2[i])
loop_time = time.time() - start

# 方法2:列表推导
start = time.time()
result_listcomp = [list1[i] + list2[i] for i in range(n)]
listcomp_time = time.time() - start

# 方法3:zip+列表推导
start = time.time()
result_zip = [a + b for a, b in zip(list1, list2)]
zip_time = time.time() - start

循环基准 2/2:NumPy 与等价性

Listing 12
展开NumPy实现与等价性核对
# 方法4:NumPy向量化
arr1 = np.array(list1)
arr2 = np.array(list2)
start = time.time()
result_numpy = arr1 + arr2
numpy_time = time.time() - start

print(f'Python循环:  {loop_time:.4f}秒')
print(f'列表推导:    {listcomp_time:.4f}秒')
print(f'zip方法:     {zip_time:.4f}秒')
print(f'NumPy向量化: {numpy_time:.4f}秒')
safe_numpy_time = numpy_time if numpy_time > 0 else 1e-12
assert result_loop == result_listcomp == result_zip == result_numpy.tolist()
print(f'\n当前环境本次循环/NumPy耗时比: {loop_time/safe_numpy_time:.1f};不外推固定倍数')
#print(f'\n最快方法比最慢快 {loop_time/numpy_time:.1f}倍')
Python循环:  0.0126秒
列表推导:    0.0080秒
zip方法:     0.0052秒
NumPy向量化: 0.0004秒

当前环境本次循环/NumPy耗时比: 28.3;不外推固定倍数

性能优化总结

方法 速度 适用场景
for循环 最慢 简单逻辑、学习阶段
列表推导 较快 中等规模数据
zip+推导 较快 多列表并行操作
NumPy向量化 常在同类数值批处理上更快 先基准测试规模、内存与可读性
  • NumPy 的向量化路径常能降低 Python 循环开销,但加速幅度取决于数据规模、dtype、内存布局与操作类型
  • 先用代表性负载基准测试;小数据、分支密集或流式任务可保留清晰的 Python 循环

本章核心知识回顾

知识点 关键语法 金融场景
for循环 for x in seq: 遍历股票列表
while循环 while cond: 价格监控
break 跳出循环 达到风险提醒线后停止并检查
continue 跳过当前迭代 过滤异常数据
for-else 正常结束执行else 数据完整性验证
嵌套循环 双层for 多股票多日分析

随堂练习

  • 问题 1|需要准备哪些数据?:按日期排列的价格与涨跌幅序列。
  • 问题 2|需要完成哪些操作?:运行 cell-stock-monitoring-loop,用 for、continue 与 break 逐日扫描异常。
  • 问题 3|应得到哪些结果?:逐日检查记录、首次出现预警的日期,以及没有出现预警时的结果。
  • 问题 4|怎样确认结果可靠?:与向量化布尔结果核对首次命中;日期乱序或循环无结束条件时先检查原因。
  • 问题 5|换一个情境,怎样继续应用?:把监控循环拓展应用到另一只中国股票。
  • 作答提示:请依次写清所用数据、分析过程、所得结果、核对方法和拓展思考。课程所需数据见前言中的下载入口;教学平台固定题按页面说明完成。

教师参考解答|答案与说明 1

  • 补充练习|break 首次预警

教师参考解答|代码 1

展开代码(代码区可独立滚动)
daily_returns=[0.01,-0.02,-0.045,0.05]  # 准备按时间排序的收益率
first_alert=None  # 初始化首次预警
for trading_day,return_rate in enumerate(daily_returns,start=1):  # 逐日扫描
    if abs(return_rate)>=0.03:  # 判断是否首次越过课堂阈值
        first_alert=(trading_day,return_rate)  # 保存首次命中
        break  # 找到首次事件后退出循环
print(first_alert)  # 输出第3日与对应收益率

教师参考解答|答案与说明 2

  • 解释与拓展应用答案:循环允许保留顺序并提前停止,大规模无状态筛选更适合向量化;拓展应用到长三角行情时用布尔掩码首个 True 核对,阈值须由风险制度批准。

  • 所用数据与字段:逐日收益率,绝对值阈值3%

  • 参考代码或推导(平台保护块之外):

教师参考解答|代码 2

展开代码(代码区可独立滚动)
returns=[0.01,-0.04,0.035]  # 定义输入
alerts=[(i,r) for i,r in enumerate(returns,1) if abs(r)>=0.03]  # 筛选预警
print(alerts)  # 输出序号与幅度

教师参考解答|答案与说明 3

  • 参考结果:第2、3个观测被标记
  • 边界 / 局限:预警不解释原因
  • 常见错误:漏用 abs;索引从0错位